//-----------------------------------------------------------------------
// <copyright file="ExceptionProviderUnitTest.cs" company="CodePlex">
//     Copyright (c) Doug Holland, CodePlex. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace CodePlex.Diagnostics.Providers
{
    using System;
    using System.Reflection;

    using System.Security;
    using System.Security.Principal;

    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;

    using Microsoft.VisualStudio.TestTools.UnitTesting;

    /// <summary>
    /// Provides unit testing for the <see cref="T:CodePlex.Diagnostics.ExceptionProvider"/> class and other framework exception types.
    /// </summary>
    [TestClass]
    public sealed class ExceptionProviderUnitTest
    {
        #region public ExceptionProviderUnitTest()

        /// <summary>
        /// Initializes a new instance of the <see cref="T:ExceptionProviderUnitTest"/> class.
        /// </summary>
        public ExceptionProviderUnitTest()
        {
        }

        #endregion

        #region public void DefaultExceptionProviderUnitTest()

        /// <summary>
        /// Unit test to exercise the <see cref="T:CodePlex.Diagnostics.Providers.ExceptionProvider"/> class.
        /// </summary>
        /// <remarks>
        /// Presently manual verification of the success of this test is required by reviewing the before and after state of the database.
        /// </remarks>
        [TestMethod]
        [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Inconclusive(System.String)", Justification = "CA1303 okay within unit tests")]
        public void DefaultExceptionProviderUnitTest()
        {
            try
            {
                for (int index = 0; index < 10; index++)
                {
                    index /= index;
                }

                Assert.Inconclusive("Failed to generate test exception to use for publication.");
            }
            catch (DivideByZeroException ex)
            {
                IIdentity identity = WindowsIdentity.GetCurrent() as IIdentity;
                ExceptionProvider.Publish(new TargetInvocationException(ex), identity);
            }
        }

        #endregion

        #region public void ExceptionProviderExceptionArgumentNullUnitTest()

        /// <summary>
        /// Unit test to exercise the <see cref="T:CodePlex.Diagnostics.Providers.ExceptionProvider"/> class.
        /// </summary>
        /// <remarks>
        /// The <see cref="M:CodePlex.Diagnostics.Providers.ExceptionProvider.Publish"/> method should throw an <see cref="T:System.ArgumentNullException"/> if the supplied <see cref="T:System.Exception"/> is <c>null</c>.
        /// </remarks>
        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void ExceptionProviderExceptionArgumentNullUnitTest()
        {
            IIdentity identity = WindowsIdentity.GetCurrent() as IIdentity;
            ExceptionProvider.Publish(null, identity);
        }

        #endregion

        #region public void ExceptionProviderIIdentityArgumentNullUnitTest()

        /// <summary>
        /// Unit test to exercise the <see cref="T:CodePlex.Diagnostics.Providers.ExceptionProvider"/> class.
        /// </summary>
        /// <remarks>
        /// The <see cref="M:CodePlex.Diagnostics.Providers.ExceptionProvider.Publish"/> method should throw an <see cref="T:System.ArgumentNullException"/> if the supplied <see cref="T:System.Security.Principal.IIdentity"/> is <c>null</c>.
        /// </remarks>
        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Inconclusive(System.String)", Justification = "CA1303 okay within unit tests")]
        public void ExceptionProviderIIdentityArgumentNullUnitTest()
        {
            try
            {
                for (int index = 0; index < 10; index++)
                {
                    index /= index;
                }

                Assert.Inconclusive("Failed to generate test exception to use for publication.");
            }
            catch (DivideByZeroException ex)
            {
                ExceptionProvider.Publish(new TargetInvocationException(ex), null);
            }
        }

        #endregion

        #region public void PublishedExceptionUnitTest()

        /// <summary>
        /// Unit test to exercise the <see cref="T:CodePlex.Diagnostics.PublishedException"/> class.
        /// </summary>
        /// <remarks>
        /// The <see cref="M:CodePlex.Diagnostics.Providers.ExceptionProvider.Publish"/> method should return the same publication Id when presented with a <see cref="T:CodePlex.Diagnostics.PublishedException"/>.
        /// This indicates that the <see cref="T:CodePlex.Diagnostics.PublishedException"/> is not published a second time.
        /// </remarks>
        [TestMethod]
        public void PublishedExceptionUnitTest()
        {
            try
            {
                try
                {
                    for (int index = 0; index < 10; index++)
                    {
                        index /= index;
                    }

                    Assert.Inconclusive("Failed to generate test exception to use for publication.");
                }
                catch (DivideByZeroException ex)
                {
                    IIdentity identity = WindowsIdentity.GetCurrent() as IIdentity;

                    Guid publicationId = ExceptionProvider.Publish(new TargetInvocationException(ex), identity);

                    // ensure the published exception Id is not Guid.Empty.
                    Assert.AreNotEqual<Guid>(publicationId, Guid.Empty);

                    throw new PublishedException(publicationId, new TargetInvocationException(ex));
                }
            }
            catch (PublishedException ex)
            {
                Assert.IsNotNull(ex);

                IIdentity identity = WindowsIdentity.GetCurrent() as IIdentity;

                Guid publicationId = ExceptionProvider.Publish(ex, identity);

                // ensure the two publication Id's are equal, therefore the exception was not published a second time.
                Assert.AreEqual<Guid>(ex.PublicationId, publicationId);
            }
        }

        #endregion

        #region public void PublishedFaultExceptionUnitTest()

        /// <summary>
        /// Unit test to exercise the <see cref="T:CodePlex.Diagnostics.ExceptionProvider`1"/> and <see cref="T:CodePlex.Diagnostics.ExceptionProvider"/> classes.
        /// </summary>
        /// <remarks>
        /// The <see cref="M:CodePlex.Diagnostics.Providers.ExceptionProvider.Publish"/> method should return the same publication Id when presented with a <see cref="T:CodePlex.Diagnostics.PublishedException"/>.
        /// This indicates that the <see cref="T:CodePlex.Diagnostics.PublishedException"/> is not published a second time.
        /// </remarks>
        [TestMethod]
        public void PublishedFaultExceptionUnitTest()
        {
            try
            {
                try
                {
                    for (int index = 0; index < 10; index++)
                    {
                        index /= index;
                    }

                    Assert.Inconclusive("Failed to generate test exception to use for publication.");
                }
                catch (DivideByZeroException ex)
                {
                    IIdentity identity = WindowsIdentity.GetCurrent() as IIdentity;

                    Guid publicationId = ExceptionProvider.Publish(ex, identity);

                    // ensure the published exception Id is not Guid.Empty.
                    Assert.AreNotEqual<Guid>(publicationId, Guid.Empty);

                    throw new PublishedFaultException(publicationId, ex.Message);
                }
            }
            catch (PublishedFaultException ex)
            {
                Assert.IsNotNull(ex);

                IIdentity identity = WindowsIdentity.GetCurrent() as IIdentity;

                Guid publicationId = ExceptionProvider.Publish(ex, identity);

                // ensure the two publication Id's are equal, therefore the exception was not published a second time.
                Assert.AreEqual<Guid>(ex.PublicationId, publicationId);
            }

            try
            {
                try
                {
                    for (int index = 0; index < 10; index++)
                    {
                        index /= index;
                    }

                    Assert.Inconclusive("Failed to generate test exception to use for publication.");
                }
                catch (DivideByZeroException ex)
                {
                    IIdentity identity = WindowsIdentity.GetCurrent() as IIdentity;

                    Guid publicationId = ExceptionProvider.Publish(new TargetInvocationException(ex), identity);

                    // ensure the published exception Id is not Guid.Empty.
                    Assert.AreNotEqual<Guid>(publicationId, Guid.Empty);

                    throw new PublishedFaultException<TargetInvocationException>(publicationId, new TargetInvocationException(ex));
                }
            }
            catch (PublishedFaultException<TargetInvocationException> ex)
            {
                Assert.IsNotNull(ex);

                IIdentity identity = WindowsIdentity.GetCurrent() as IIdentity;

                Guid publicationId = ExceptionProvider.Publish(ex, identity);

                // ensure the two publication Id's are equal, therefore the exception was not published a second time.
                Assert.AreEqual<Guid>(ex.PublicationId, publicationId);
            }
        }

        #endregion

        #region public void UnhandledExceptionUnitTest()

        /// <summary>
        /// Unit test to exercise the <see cref="T:CodePlex.Diagnostics.UnhandledException"/> class.
        /// </summary>
        [TestMethod]
        [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Inconclusive(System.String)", Justification = "CA1303 okay within unit tests")]
        public void UnhandledExceptionUnitTest()
        {
            try
            {
                for (int index = 0; index < 10; index++)
                {
                    index /= index;
                }

                Assert.Inconclusive("Failed to generate test exception to use for publication.");
            }
            catch (DivideByZeroException ex)
            {
                IIdentity identity = WindowsIdentity.GetCurrent() as IIdentity;

                // use the UnhandledException class as it would be used within an AppDomain.UnhandledException event handler.
                ExceptionProvider.Publish(new UnhandledException(ex), identity);
            }
        }

        #endregion

        #region public void ThreadExceptionUnitTest()

        /// <summary>
        /// Unit test to exercise the <see cref="T:CodePlex.Diagnostics.ThreadException"/> class.
        /// </summary>
        [TestMethod]
        [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Inconclusive(System.String)", Justification = "CA1303 okay within unit tests")]
        public void ThreadExceptionUnitTest()
        {
            try
            {
                for (int index = 0; index < 10; index++)
                {
                    index /= index;
                }

                Assert.Inconclusive("Failed to generate test exception to use for publication.");
            }
            catch (DivideByZeroException ex)
            {
                IIdentity identity = WindowsIdentity.GetCurrent() as IIdentity;

                // use the UnhandledException class as it would be used within an Application.ThreadException event handler.
                ExceptionProvider.Publish(new ThreadException(ex), identity);
            }
        }

        #endregion
    }
}

